﻿/*
 * Copyright 2010 Marc Cesarine
 * 
 * This file is part of Ssh Commander.

 * Ssh Commander is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * Ssh Commander is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with Ssh Commander.  If not, see <http://www.gnu.org/licenses/>.
 */

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System;
using System.Threading;

namespace SshCommander
{
    public class ServersList
    {
        private ObservableCollection<Server> serverslist_v;
        private ObservableCollection<Account> accountslist_v;
        private List<Tunnel> tunnelslist_v;
        private List<int> usedports_v;

        public ServersList()
        {
            serverslist_v = new ObservableCollection<Server>();
            accountslist_v = new ObservableCollection<Account>();
            tunnelslist_v = new List<Tunnel>();
            usedports_v = new List<int>();
        }

        public void addServer(Server server)
        {
            serverslist_v.Add(server);
            server.setUsedPorts(ref usedports_v);
        }

        public void addAccount(Account account)
        {
            accountslist_v.Add(account);
        }

        public void addTunnel(Tunnel tunnel)
        {
            tunnelslist_v.Add(tunnel);
        }

        public void linkServerAccount(string serverId, string accountId)
        {
            int serverIndex = -1;
            int accountIndex = -1;

            bool Found = false;
            int i = 0;
            while ((!Found) && (i < serverslist_v.Count))
            {
                if (serverslist_v[i].id == serverId)
                {
                    Found = true;
                    serverIndex = i;
                }
                i++;
            }

            Found = false;
            i = 0;
            while ((!Found) && (i < accountslist_v.Count))
            {
                if (accountslist_v[i].id == accountId)
                {
                    Found = true;
                    accountIndex = i;
                }
                i++;
            }

            if ((serverIndex != -1) && (accountIndex != -1))
            {
                //Add account to server accounts
                Account newaccount = accountslist_v[accountIndex].Clone();
                newaccount.hostname = serverslist_v[serverIndex].hostname;
                serverslist_v[serverIndex].accounts.Add(newaccount);
            }
        }

        public void linkServerTunnel(string serverId, string tunnelId)
        {
            int serverIndex = -1;
            int tunnelIndex = -1;

            // Find server in list
            bool Found = false;
            int i = 0;
            while ((!Found) && (i < serverslist_v.Count))
            {
                if (serverslist_v[i].id == serverId)
                {
                    Found = true;
                    serverIndex = i;
                }
                i++;
            }

            // Find tunnel in list
            Found = false;
            i = 0;
            while ((!Found) && (i < tunnelslist_v.Count))
            {
                if (tunnelslist_v[i].id == tunnelId)
                {
                    Found = true;
                    tunnelIndex = i;
                }
                i++;
            }

            if ((serverIndex != -1) && (tunnelIndex != -1))
            {
                // Get server and tunnel
                Tunnel tunnel = tunnelslist_v[tunnelIndex];
                Server server = serverslist_v[serverIndex];

                //Add tunnel details to server
                server.tunnel_hostname = tunnel.hostname;
                server.tunnel_username = tunnel.username;
                server.tunnel_password = tunnel.password;

                server.isTunneled = true;
            }
        }

        public void Clear()
        {
            serverslist_v.Clear();
            accountslist_v.Clear();
        }

        public ObservableCollection<Server> serversList
        {
            get
            {
                return serverslist_v;
            }
        }

        public ObservableCollection<Account> accountsList
        {
            get
            {
                return accountslist_v;
            }
        }

        public void ServersConnectivityThreadPoolCallback(Object threadContext)
        {            //Tableau des ResetEvent pour connaître l'état d'avancement des threads
            ManualResetEvent[] doneEvents = new ManualResetEvent[serverslist_v.Count];

            //On fait un thread par test à effectuer
            //for (int i = 0; i < serversList_v.serversList.Count; i++)
            int i = 0;
            foreach (Server server in serverslist_v)
            {
                //On initialise le ResetEvent du thread
                doneEvents[i] = new ManualResetEvent(false);

                server.doneevent = doneEvents[i];
                //On crée l'objet Server Threadé
                //Server Server = new Server(doneEvents[i]);
                //Server.Name = ServeursList[i].Name;
                //Server.Connectivite = ServeursList[i].Connectivite;
                //Server.Port = ServeursList[i].Port;

                if (server.isTunneled)
                {
                    //On lance le traitement dans un thread spécifique (utilisation d'un pool de threads)
                    ThreadPool.QueueUserWorkItem(server.ConnectivityTunnelThreadPoolCallback, doneEvents[i]);
                }
                else
                {
                    //On lance le traitement dans un thread spécifique (utilisation d'un pool de threads)
                    ThreadPool.QueueUserWorkItem(server.ConnectivityThreadPoolCallback, doneEvents[i]);
                }
                i++;
            }

            /*foreach (WaitHandle Handle in doneEvents)
            {
                Handle.WaitOne();
            }*/

            // Wait for all threads in pool to finish...
            WaitHandle.WaitAll(doneEvents);

        }
    }

    public class Tunnel
    {
        private string hostname_v;
        private string username_v;
        private string password_v;
        private string id_v;

        public Tunnel()
        {

        }

        public string hostname
        {
            get
            {
                return hostname_v;
            }
            set
            {
                hostname_v = value;
            }
        }

        public string username
        {
            get
            {
                return username_v;
            }
            set
            {
                username_v = value;
            }
        }

        public string password
        {
            get
            {
                return password_v;
            }
            set
            {
                password_v = value;
            }
        }

        public string id
        {
            get
            {
                return id_v;
            }
            set
            {
                id_v = value;
            }
        }
    }
}
